/* 
 * CMPS 258: Programming Languages
 *        Assignment 3 - Part1: "Tanks" - March 20, 2008
 *        Group name: Doomsday
 *        Authors:  Ramsey Nasser (ID# 200600496) 
 *                  Hadi Abu Rislan (ID# 200600426) 
 *                  Kevin Azzam (ID# 200602033)
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*
 * NOTES: 
 *   - Compile with -lm linker option in gcc (to link the math library to use sqrt) 
 *
 * TO DO: 
 * 
 */

float solve(float a, float b, float c, float d); // custom equation solver

int main() {
    FILE *in, *out, *tmp; 
    
    tmp = fopen("tanks.in", "r"); 
    if (tmp == NULL) {
       fprintf(stderr, "Coulnd't find input file. Program Terminating. \n"); 
       system("pause");
       exit(1); 
    }
    
    int i, j, k = j = i = 0;
    
    int iCases = 0; 
    
    while (!feof(tmp)) {
         int n = 0; // store temp number of tanks here. 
         float junk; // store things to skip here
         fscanf(tmp, "%d", &n); 
         if (n == 0)
              break; 
         iCases++; 
         for (i = 0; i < n+n-1; i++)
              fscanf(tmp, "%fd", &junk); 
    }
    fclose(tmp); 
    
    out = fopen("tanks.out", "w");  // clear contents of output file. 
    fclose(out); 
    out = fopen("tanks.out", "a"); 
         
    in = fopen("tanks.in", "r"); 
    if (in == NULL) {
       fprintf(stderr, "Coulnd't find input file. Program Terminating. \n"); 
       system("pause");
       exit(1); 
    }
    
    
    for (k = 0; k < iCases; k++) { 
         float answer = 0; 
         int totalTanks; 
         fscanf(in, "%d", &totalTanks); 

         float *tankHeight, *linkHeight; 
         tankHeight = (float*)malloc(sizeof(float) * totalTanks); 
         linkHeight = (float*)malloc(sizeof(float) * totalTanks-1);

         for (i = 0; i < totalTanks; i++) 
             fscanf(in, "%f", &tankHeight[i]); 
         for (i = 0; i < totalTanks-1; i++)
             fscanf(in, "%f", &linkHeight[i]);
         
         /*let's work on the case where there is no recursion, we only have two tanks*/
         // tank1 has 1 atmosphere
         int tank; 
         float Pfloor = 1.0 + 0.097*tankHeight[0]; 
         float *Pair, *waterHeight; 
         Pair = (float*)malloc(sizeof(float) * totalTanks); 
         waterHeight = (float*)malloc(sizeof(float) * totalTanks); 
         Pair[0] = Pair [1] = 1.0;
         waterHeight[0] = tankHeight[0]; // should we set this now or in the end.. does it matter? (base case? )
         for (i = 1; i < totalTanks; i++) {
              Pair[i] = 1.0; 
              waterHeight[i] = 0.0; 
         }
         
         int lastTank = totalTanks - 1; // last tank to be filled is the last tank by default. 
         int back = 0; // are we going forwards or backwards in the loop? (once we reach last tank, we go back and fill the remains)
         //int first = 1; 
         
         Pfloor = Pair[0] + 0.097*waterHeight[0]; // waterheight[0] was initialized to tankheight[0]
         for (tank = 1; tank < totalTanks; tank++) { 
             if (tank < 1)
                  break; 
             if (tank == lastTank) 
                  back = 1; 
             printf("Tank is: %i\n", tank); 
             // pfloor at tank0 = pfloor at tank1
             // also, p1v1 = p2v2
             float p1, v1, p2, v2 = p2 = p1 = v1 = 0.0; 
             
             if (back == 0) { // we're still going forwards... 
                  // check previous, check next. If first tank, we don't check previous. 
                  if (tank != 1) {
                       // check previous
                       p1 = Pair[tank-1]; 
                       v1 = 0; 
                       for (i = tank; i < totalTanks; i++) {
                            v1 += tankHeight[i]; 
                       }
                       v1 += tankHeight[tank-1] - waterHeight[tank-1];
                       v2 = v1 - linkHeight[tank-1]; 
                       printf("p1: %f\nv1: %f\np2: %f\nv2: %f\n", p1, v1, p2, v2); 
                       p2 = p1*v1/v2; 
                       float p2max = 1 + 0.097*(tankHeight[0]-linkHeight[tank-1]); 
                       if (p2 < p2max) {
                          printf("we can fill %i to %f -- p2: %f  p2max: %f\n", tank, linkHeight[tank-1], p2, p2max); 
                          waterHeight[tank] = linkHeight[tank-1]; 
                          Pair[tank-1] = Pair[tank] = p2; 
                       }
                       else {
                            printf("we can't fill %i to %f -- p2: %f, only to p2max: %f\n", tank, linkHeight[tank-1], p2, p2max); 
                            Pair[tank-1] = Pair[tank] = p2max; 
                            waterHeight[tank] = solve(0.097, -Pfloor-0.097*(v2+linkHeight[tank]), Pfloor*(v2+linkHeight[tank])-p1*v1, tankHeight[tank]); 
                            // are the params for solve correct? 
                            printf("we can fill instead till: %f", waterHeight[tank]); 
                            lastTank = tank; 
                            back = 1; 
                            tank =-1; 
                       }
                  }
                  if (back == 0) {
                       // check next
                       p1 = Pair[tank]; 
                       v1 = 0; 
                       for (i = tank; i < totalTanks; i++)
                            v1 += tankHeight[i]; 
                       v1 -= linkHeight[tank-1]; 
                       v2 = v1 - linkHeight[tank] + linkHeight[tank-1]; /* assume we filled tank till the next linkHeight. 
                       we want to check if we have enough pressure to do so. if so, we fill till that height, then go on and 
                       proceed in doing the same for the following tanks. Otherwise, we reached our max, and we have to go 
                       back to the previous tanks and continue filling them to reach their max. */ 
                       p2 = p1*v1/v2; // p2 if we fill till linkHeight[tank]
                       printf("p1: %f\nv1: %f\np2: %f\nv2: %f\n", p1, v1, p2, v2); 
                       float p2max = 1+0.097*(tankHeight[0]-linkHeight[tank]); 
                       if (p2 < p2max) {
                          printf("we can fill more! %i to %f -- p2: %f  p2max: %f\n", tank, linkHeight[tank], p2, p2max); 
                          waterHeight[tank] = linkHeight[tank]; 
                          Pair[tank] = p2; 
                          continue; 
                       }
                       else { 
                            printf("we can't fill more! :( -- p2: %f  p2max: %f\n", p2, p2max); 
                            waterHeight[tank] = solve(0.097, -Pfloor-0.097*(v2+linkHeight[tank]), Pfloor*(v2+linkHeight[tank])-p1*v1, tankHeight[tank]); 
                            if (waterHeight[tank] == -1) { 
                               printf("An error occured in calculating the quadratic equation... Terminating. "); 
                               system("pause"); 
                               exit(1);
                            }
                            printf("we can fill till: %f", waterHeight[tank]); 
                            Pair[tank] = Pfloor - 0.097*waterHeight[tank]; 
                            lastTank = tank; 
                            // go back and update the rest
                            back = 1; 
                            tank-=1; 
                       }
                  }
             } // end if back --> ie we're now going backwards
             if (tank == totalTanks-1) {
                  p1 = Pair[tank]; 
                  printf("\nPair is: %f\n", p1); 
                  v1 = tankHeight[tank] - linkHeight[tank-1]; 
                  //for (i = tank+1; i < totalTanks; i++) 
                  //     v1 += tankHeight[i] - waterHeight[i]; // waterHeight[i] here is always zero. 
                  //v1 += tankHeight[tank-1] - waterHeight[tank-1];
             }
             else {
                  p1 = Pair[tank]; 
                  v1 = tankHeight[tank] - linkHeight[tank]; 
             }
             printf("Tank is: %i\n", tank); 
             printf("pressure in T1: %f\n", Pair[tank]); 
             /*if (first == 1)
                  first = 0; 
             else {
                  p1 = Pair[tank]; 
                  v1 = linkHeight[tank]; 
             }*/
             //p1 = 
             waterHeight[tank] = solve(0.097, -Pfloor-0.097*tankHeight[tank], Pfloor*tankHeight[tank]-p1*v1, tankHeight[tank]); 
             printf("A: %f\nB: %f\nC: %f\nHeight: %f\n", 0.097, -Pfloor-0.097*tankHeight[tank], Pfloor*tankHeight[tank]-p1*v1, tankHeight[tank]);
             if (waterHeight[tank] == -1) {
                printf("An error occured in calculating the quadratic equation... Terminating. "); 
                system("pause"); 
                exit(1);
             }
             Pair[tank] = Pfloor - 0.097*waterHeight[tank]; 
             tank-=2; 
             //p2 = pAir[tank]; 
             //v2 = v1-waterHeight[tank] //OR v1 -waterHeight[tank] - loop through all the other volumes
             //p1v1 = p2v2
             //pAir[tank] = p1v1/(tankHeight[tank]-((Pfloor-pAir[tank])/0.097));
             //pAir[tank] = p1v1/(v1-waterHeight[tank]);
             //pAir[tank] = Pfloor - 0.097*waterHeight[tank]; 
             // Pfloor - 0.097*waterHeight[tank] = p1v1/(tankHeight[tank]-waterHeight[tank]); 

             printf("%f\n", Pair[tank]);
         }
         
         for (i = 0; i < totalTanks; i++) 
             answer += waterHeight[i]; 
              
         free(Pair); 
         free(tankHeight); 
         free(linkHeight); 
         
         fprintf(out, "Case %i: %f\n\n", k+1, answer); 
         printf("Case %i: %f\n\n", k+1, answer); 
    }
    
    fclose(in); 
    fclose(out); 
    //system("pause"); 
    return (EXIT_SUCCESS);
}

float solve(float a, float b, float c, float d) {
     float x1, x2 = x1 = 0.0; 
     x1 = (-b + (sqrt(pow(b,2)-(4*a*c))))/(2*a);
     x2 = (-b - (sqrt(pow(b,2)-(4*a*c))))/(2*a);
     if (x1 < d)
        return x1; 
     else if (x2 < d)
             return x2; 
     else return -1; 
}
